package cs236369.webserver;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Properties;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.entity.StringEntity;

public class TSPEngine implements TypeHandler {
	static private Integer counter = 0;
	private Properties props = null;

	/*
	 * Got 2 add a constructor that receives a Properties argument.
	 */
	public TSPEngine(Properties _props)
	{
		this.props = _props;
	}
	
	public static String createJavaCode(String path, String id) {
		Log.out("TSPEngine: [createJavaCode] called...");
		byte[] buffer = new byte[(int) new File(path).length()];
		FileInputStream f;
		try {
			f = new FileInputStream(path);
			f.read(buffer);
		} catch (Exception e) {
			Log.err("TSPEngine: [createJavaCode] File "+e.toString());
		}
		String tspString = new String(buffer);
		String result = new String();

		result += "package cs236369.webserver;\npublic class TSPClass" + id
				+ " implements TSPI {\n";
		result += "public void generateHtml(java.util.HashMap<String,String> params, Session session, java.io.PrintStream out) throws java.lang.Exception{\n ";
		String[] split1 = tspString.split("\\<\\?");
		try {
			result += ("out.print(java.net.URLDecoder.decode(\""
					+ URLEncoder.encode(split1[0], "UTF-8") + "\",\"UTF-8\"));\n");
		} catch (UnsupportedEncodingException e) {
			Log.err("TSPEngine: [createJavaCode] Encoder1 "+e.toString());
		}
		for (int i = 1; i < split1.length; i++) {
			String[] split2 = split1[i].split("\\?\\>");
			result += split2[0] + "\n";
			if (split2.length == 2) {
				try {
					result += ("out.print(java.net.URLDecoder.decode(\""
							+ URLEncoder.encode(split2[1], "UTF-8") + "\",\"UTF-8\"));\n");
				} catch (UnsupportedEncodingException e) {
					Log.err("TSPEngine: [createJavaCode] Encoder2 "+e.toString());
				}
			}
		}
		result += "\n}\n}\n";
		Log.out("TSPEngine: [createJavaCode] completed...");
		return result;
	}

	public void handle(Request request, HttpResponse response) {
		Log.out("================( Handeling TSP page )=================");
		Header[] headers = request.getHeaders();
		Boolean flag = false;
		Session session = null;
		for (Header header:headers) {
			if (header.getName().equals("Cookie")) {
				flag = true;
				session = WebServer.sessionMap.getSession(SessionMap.getSessionKey(header.getValue()));
				Log.details("sessionkey: "+SessionMap.getSessionKey(header.getValue()));
				Log.details("header: "+header.getValue());
				break;
			}
		}
		if ((!flag) || (session == null) || (!session.isValid())){
			session = new Session();
			String key = WebServer.sessionMap.addSession(session);
			response.addHeader("Set-Cookie","sessionkey="+key);
		}
				
		String path = (String) request.getPath();
		String id;
		File javaFile = null;
		File classFile = null;
		synchronized (counter) {
			id = String.valueOf(counter);
			counter++;
		}
		try {
			String code = createJavaCode(path, id);
			HashMap<String, String> params = request.getParams();
			javaFile = new File("src/cs236369/webserver/TSPClass"+id+".java");
			FileWriter fwriter = new FileWriter(javaFile);
			fwriter.write(code);
			fwriter.close();
			/*
			 * Compile & Load the code
			 */
			Log.out("TSPEngine: compiling and loading");
			JavaCompile jc = new JavaCompile(props.getProperty("jre_path"));
			Class<?> a = jc.compileAndLoad("src/cs236369/webserver/TSPClass"+id+".java",
					"cs236369.webserver.TSPClass"+id);
			Log.out("TSPEngine: instantiating " + a.getName());
			Object o = a.newInstance();
			Method m = a.getDeclaredMethod("generateHtml", new Class<?>[]{HashMap.class,Session.class,PrintStream.class});
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			PrintStream out = new PrintStream(os);
			Object paramsObj[] = {params,session,out};
			Log.out("TSPEngine: Invoking page creator");
			try {
				m.invoke(o,paramsObj);
			} catch (Exception e) {
				Log.out("TSPEngine: bad session, out or params");
				RequestHandlerThread.handleBadRequest(response, "Trouble creating dynamic content", HttpStatus.SC_NOT_FOUND);
				return;
			}
			response.setEntity(new StringEntity(os.toString()));
			counter++;
		} catch (IOException e) {
			Log.err("TSPEngine: (IOException) "+e.toString());
			RequestHandlerThread.handleBadRequest(response, "Trouble creating dynamic content", HttpStatus.SC_INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			Log.err("TSPEngine: Unkown exception"+e.toString());
			RequestHandlerThread.handleBadRequest(response, "Trouble creating dynamic content", HttpStatus.SC_INTERNAL_SERVER_ERROR);
		} finally {
			javaFile = new File("TSPClass" + id + ".java");
			classFile = new File("bin\\handlers\\TSPClass" + id + ".class");
			if (javaFile.exists())
				javaFile.delete();
			if (classFile.exists())
				classFile.delete();
		}
		
	}
}